﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using MyUtils;

namespace Test.MyUtils.WeakDelegateTest2
{
	[TestClass]
	public class Weak_delegate_tests
	{
		readonly Publisher _publisher = new Publisher();

		[TestMethod]
		public void Should_display_property_changed()
		{
			var subscriber = new ConsoleDisplaySubscriber(_publisher);
			Assert.AreEqual(1, _publisher.SubscribersCount);
			Assert.AreEqual(0, subscriber.Calls);
			_publisher.Property = "asd";
			Assert.AreEqual(1, subscriber.Calls);
			var wr = new WeakReference(subscriber);
			subscriber = null;
			GC.Collect();
			Assert.AreEqual(false, wr.IsAlive);
			_publisher.Property = "one extra call for collecting died subscribers";
			Assert.AreEqual(0, _publisher.SubscribersCount);
		}

	}

	class Publisher : INotifyPropertyChanged
	{
		string _property;

		public string Property
		{
			get { return _property; }
			set
			{
				_property = value;
				OnPropertyChanged("Property");
			}
		}

		public int SubscribersCount
		{
			get
			{
				var pc = PropertyChanged;
				if ( pc== null)
				{
					return 0;
				}
				return (int)pc.Reflect("GetInvocationList.Length");
			}
		}

		#region Implementation of INotifyPropertyChanged

		public event PropertyChangedEventHandler PropertyChanged;

		public void OnPropertyChanged(string name)
		{
			var handler = PropertyChanged;
			if (handler != null)
			{
				handler(this, new PropertyChangedEventArgs(name));
			}
		}

		#endregion
	}

	class ConsoleDisplaySubscriber
	{
		readonly Publisher _pub;

		public ConsoleDisplaySubscriber(Publisher pub)
		{
			_pub = pub;
			// pub.PropertyChanged += WeakEventHandler.Create<PropertyChangedEventHandler>(Display, x => pub.PropertyChanged -= x);
			// Weak.MagicSubscribe(pub, "PropertyChanged", (PropertyChangedEventHandler)Display);
			// Weak.MagicSubscribe(pub, "PropertyChanged", "Display");

			// FULL SYNTAX
			//Weak.MagicSubscribe<PropertyChangedEventHandler>(x => pub.PropertyChanged += x, x => pub.PropertyChanged -= x, Display);

			// SHORT SYNTAX
			Weak.MagicSubscribe(() => pub.PropertyChanged -= Display);
		}

		void Subscribing()
		{
			_pub.PropertyChanged += Display;
		}

		void Display(object sender, PropertyChangedEventArgs e)
		{
			Calls++;
			Console.WriteLine("Property Changed: " + e.PropertyName);
		}

		public int Calls;
	}
}
